/*****************************************************************************
*                  Shanghai ChipON Micro-Electronic Co.,Ltd                  *
******************************************************************************
*  @File Name        : I2C.c                                                 *
*  @Author           : ChipON AE/FAE Group                                   *
*  @Data$            : 2021-07-14                                            *
*  @Version          : V2.0                                                  *
*  @Description      : This file contains the I2C configuration for KF32A156 *
******************************************************************************
*  Copyright (C) by Shanghai ChipON Micro-Electronic Co.,Ltd                 *
*  All rights reserved.                                                      *
*                                                                            *
*  This software is copyright protected and proprietary to                    *
*  Shanghai ChipON Micro-Electronic Co.,Ltd.                                 *
******************************************************************************
*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
*                          REVISON HISTORY                                   *
*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
*  Data       Version  Author        Description                             *
*  ~~~~~~~~~~ ~~~~~~~~ ~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
*  2021-07-14 00.02.00  AE Group     Version 2.0 update                      *
*                                                                            *
*                                                                            *
*****************************************************************************/

/******************************************************************************
**                             Include Files                                **
******************************************************************************/
#include "I2C.h"

/*****************************************************************************
**                         Private Macro Definitions                        **
*****************************************************************************/

/*****************************************************************************
**                         Private Variables Definitions                    **
*****************************************************************************/
I2C_SFRmap *I2C_Choose;
/*****************************************************************************
**                         Global Variables Definitions                    **
*****************************************************************************/
volatile uint8_t AckTimeoutFlag = 0;
/*****************************************************************************
**                             Private Functions                            **
*****************************************************************************/
static void Wait_Ack_Flag(void);
/*****************************************************************************
**                             Global Functions                            **
*****************************************************************************/
/**
 *  @brief: Initialization I2C IO
 *  @param in: None
 *  @param out : None
 *  @retval : None
 */
void I2c_IO_Init()
{
    GPIO_InitTypeDef GpioConfigPtr;

    /* Configure GPIO remapping function */
    GpioConfigPtr.m_Mode = GPIO_MODE_RMP;
    /* Configyre GPIO open drain output */
    GpioConfigPtr.m_OpenDrain = GPIO_POD_OD;
    /* PG0,SCL */
    GpioConfigPtr.m_Pin = GPIO_PIN_MASK_0;
    /* Configure pull up */
    GpioConfigPtr.m_PullUp = GPIO_PULLUP;
    /* Configure drop down */
    GpioConfigPtr.m_PullDown = GPIO_NOPULL;
    /* Configure PG0 as I2C0 SCL */
    GPIO_Pin_RMP_Config(GPIOG_SFR, GPIO_Pin_Num_0, GPIO_RMP_AF5);

    GPIO_Configuration(GPIOG_SFR, &GpioConfigPtr);

    /* PF15,SDA */
    GpioConfigPtr.m_Pin = GPIO_PIN_MASK_15;

    /* Configure PF15 as I2C0 SDA */
    GPIO_Pin_RMP_Config(GPIOF_SFR, GPIO_Pin_Num_15, GPIO_RMP_AF5);
    GPIO_Configuration(GPIOF_SFR, &GpioConfigPtr);
}

/**
 *  @brief: Initialization I2C HW module
 *  @param in: I2Cx
 *             I2c_Address
 *  @param out : None
 *  @retval : None
 */
void I2c_Init(I2C_SFRmap *I2cx)
{
    I2C_InitTypeDef I2cConfigPtr;

    /* I2c mode */
    I2cConfigPtr.m_Mode = I2C_MODE_I2C;
    /* I2c clock */
    I2cConfigPtr.m_ClockSource = I2C_CLK_SCLK;
/* Configure slave address width */
#if (I2C_ADDRESS_WIDTH == I2C_7BIT)
    I2cConfigPtr.m_BADR10 = I2C_BUFRADDRESS_7BIT;
#else
    I2cConfigPtr.m_BADR10 = I2C_BUFRADDRESS_10BIT;
#endif
    /* SMBus type */
    I2cConfigPtr.m_MasterSlave = I2C_MODE_SMBUSHOST;
    /* I2c baud rate low level time */
    I2cConfigPtr.m_BaudRateL = 115;
    /* I2c baud rate high level time */
    I2cConfigPtr.m_BaudRateH = 115;
    /* Enable ACK */
    I2cConfigPtr.m_AckEn = TRUE;
    /* Select the response signal as ACK */
    I2cConfigPtr.m_AckData = I2C_ACKDATA_ACK;

    I2C_Reset(I2cx);
    /* Configue I2C */
    I2C_Configuration(I2cx, &I2cConfigPtr);

    //    /* Enable I2C HW module */
    I2C_Cmd(I2cx, TRUE);
    /* Clear Interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2cx);

    /* Enable I2C address match */
    I2C_MATCH_ADDRESS_Config(I2cx, TRUE);

    /* Enable I2C HW module */
    I2C_Cmd(I2cx, TRUE);
}

/**
 *  @brief: Waiting for ACK signal
 *  @param in: None
 *  @param out : None
 *  @retval : None
 */
static void Wait_Ack_Flag(void)
{
	AckTimeoutFlag = 0;
	uint16_t AckWaitTime = 0xffff;
    while (I2C_Get_Ack_Fail_Flag(I2C_Choose)&&(--AckWaitTime));
    if(AckWaitTime == 0)
    {
        /* Stop bit */
        I2C_Generate_STOP(I2C_Choose, TRUE);
        /* Clear the ISIF bit of the I2C interrupt flag */
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);
        /* Wait for the stop to complete */
        while (!I2C_Get_INTERRUPT_Flag(I2C_Choose));
        /* Clear the ISIF bit of the I2C interrupt flag */
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);
        /* Clear the I2C ack fail flag AFIF bit */
        I2C_Clear_Ack_Fail_Flag(I2C_Choose);
        /* Clear the I2C stop flag PIF bit */
        I2C_Clear_Stop_Flag(I2C_Choose);
        /* Stop I2C module */
        I2C_Cmd(I2C_Choose, FALSE);
    	AckTimeoutFlag = 1;
    }
}

/**
 *  @brief: I2c Write a byte of data
 *  @param in: Write_i2c_Addr
 *             I2C_data
 *  @param out : None
 *  @retval : None
 */
void I2C_Byte_Write(uint16_t Write_i2c_Addr, uint32_t I2C_data)
{
    I2C_Choose = I2C0_SFR;

    static uint8_t I2C_SLAVE_ADDRESS10BH = 0;
    static uint8_t I2C_SLAVE_ADDRESS10BL = 0;

    /* Send data */
    /* Enable I2C HW module*/
    I2C_Cmd(I2C_Choose, TRUE);
    /* Clear interrupt flag ISIF */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);

    /* Start bit */
    I2C_Generate_START(I2C_Choose, TRUE);
    /* Wait for the start signal to stabilize */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;

#if (I2C_ADDRESS_WIDTH == I2C_10BIT)

    /* Low 8 bit register address */
    I2C_SLAVE_ADDRESS10BL = Write_i2c_Addr & 0xff;
    /* High bit address */
    I2C_SLAVE_ADDRESS10BH = (Write_i2c_Addr >> 8) & 0xff;
    /* Send slave address */
    I2C_SendData(I2C_Choose, I2C_SLAVE_ADDRESS10BH);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;

    /* Send slave 10-bit low address */
    I2C_SendData(I2C_Choose, I2C_SLAVE_ADDRESS10BL);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Determine whether there is an ACK response, if not, resend, if there is, continue to send */
    Wait_Ack_Flag();
    if(AckTimeoutFlag == 1)
    {
    	return (void)0;
    }

#else
    /* Send 7-bit slave address */
    I2C_SendData8(I2C_Choose, Write_i2c_Addr);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Determine whether there is an ACK response, if not, resend, if there is, continue to send */
    Wait_Ack_Flag();
    if(AckTimeoutFlag == 1)
    {
    	return (void)0;
    }
#endif

    /* Send data*/
    I2C_SendData(I2C_Choose, I2C_data);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;

    /* Stop bit */
    I2C_Generate_STOP(I2C_Choose, TRUE);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for the stop to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Clear the I2C stop flag PIF bit */
    I2C_Clear_Stop_Flag(I2C_Choose);
    /* Stop I2C module */
    I2C_Cmd(I2C_Choose, FALSE);
}

/**
 *  @brief: I2C write multiple bytes of data
 *  @param in: Write_i2c_Addr
 *             p_buffer
 *             number_of_byte
 *  @param out : None
 *  @retval : None
 */
void I2C_Buffer_write(uint16_t Write_i2c_Addr, uint8_t *p_buffer, uint16_t number_of_byte)
{
    I2C_Choose = I2C0_SFR;

    /* Send data */

    /* Clear interrupt flag ISIF */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    //
    /* Enable I2C HW module*/
    I2C_Cmd(I2C_Choose, TRUE);

    /* Start bit */
    I2C_Generate_START(I2C_Choose, TRUE);
    /* Wait for the start signal to stabilize */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;

#if (I2C_ADDRESS_WIDTH == I2C_10BIT)

    static uint8_t I2C_SLAVE_ADDRESS10BH = 0;
    static uint8_t I2C_SLAVE_ADDRESS10BL = 0;

    /* Low 8 bit register address */
    I2C_SLAVE_ADDRESS10BL = Write_i2c_Addr & 0xff;
    /* High bit address */
    I2C_SLAVE_ADDRESS10BH = (Write_i2c_Addr >> 8) & 0xff;
    /* Send slave address */
    I2C_SendData(I2C_Choose, I2C_SLAVE_ADDRESS10BH);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;

    /* Send slave 10-bit low address */
    I2C_SendData(I2C_Choose, I2C_SLAVE_ADDRESS10BL);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Determine whether there is an ACK response, if not, resend, if there is, continue to send */
    Wait_Ack_Flag();
    if(AckTimeoutFlag == 1)
    {
    	return (void)0;
    }

#else
    /* Send 7-bit slave address */
    I2C_SendData8(I2C_Choose, Write_i2c_Addr);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Determine whether there is an ACK response, if not, resend, if there is, continue to send */
    Wait_Ack_Flag();
    if(AckTimeoutFlag == 1)
    {
    	return (void)0;
    }
#endif

    /* Write data cyclically */
    while (number_of_byte--)
    {
        /* Send data */
        I2C_SendData8(I2C_Choose, *p_buffer);
        /* Clear the ISIF bit of the I2C interrupt flag */
        I2C_Clear_INTERRUPT_Flag(I2C_Choose);
        /* Point to the next byte to be written */
        p_buffer++;
        /* ISIF will be set to 1 when the Buff is read */
        while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
            ;
    }

    /* Stop bit */
    I2C_Generate_STOP(I2C_Choose, TRUE);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for the stop to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;

    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Clear the I2C stop flag PIF bit */
    I2C_Clear_Stop_Flag(I2C_Choose);
    /* Stop I2C module */
    I2C_Cmd(I2C_Choose, FALSE);
}

/**
 *  @brief: I2C Read one byte of data
 *  @param in: Read_I2C_Addr
 *             p_buffer
 *             number_of_byte
 *  @param out : None
 *  @retval : None
 */
void I2C_byte_read(uint16_t Read_i2c_Addr, uint32_t I2C_data)
{

    I2C_Choose = I2C0_SFR;
    static uint8_t I2C_SLAVE_ADDRESS10BH = 0;
    static uint8_t I2C_SLAVE_ADDRESS10BL = 0;

    /* Enable I2c module */
    I2C_Cmd(I2C_Choose, TRUE);
    /* Start bit */
    I2C_Generate_START(I2C_Choose, TRUE);
    /* Wait for the start signal to stabilize */
    while (!I2C_Get_Start_Flag(I2C_Choose))
        ;

#if (I2C_ADDRESS_WIDTH == I2C_10BIT)
    /* Low 8 bit register address */
    I2C_SLAVE_ADDRESS10BL = Read_i2c_Addr & 0xff;
    /* High bit address */
    I2C_SLAVE_ADDRESS10BH = (Read_i2c_Addr >> 8) & 0xff;
    /* Send slave address */
    I2C_SendData(I2C_Choose, I2C_SLAVE_ADDRESS10BH | 0x01);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;

    /* Send slave 10-bit low address */
    I2C_SendData(I2C_Choose, I2C_SLAVE_ADDRESS10BL);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Determine whether there is an ACK response, if not, stop, if there is, continue to send */
    while (I2C_Get_Ack_Fail_Flag(I2C_Choose))
        ;

#else
    /* Send 7-bit slave address */
    I2C_SendData8(I2C_Choose, Read_i2c_Addr);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Determine whether there is an ACK response, if not, stop, if there is, continue to send */
    while (I2C_Get_Ack_Fail_Flag(I2C_Choose))
        ;
#endif
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);

    /* Read a data from I2C */
    I2C_data = I2C_ReceiveData(I2C_Choose);
    /* ISIF will be set to 1 when the Buff is read */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Then clear the ISIF bit after reading */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Reply ACK after reading the data */
    I2C_Ack_DATA_Config(I2C_Choose, I2C_ACKDATA_ACK);

    /* Stop bit */
    I2C_Generate_STOP(I2C_Choose, TRUE);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for the stop to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Clear the I2C stop flag PIF bit */
    I2C_Clear_Stop_Flag(I2C_Choose);
    /* Turn off the I2C module */
    I2C_Cmd(I2C_Choose, FALSE);
}

/**
 *  @brief: I2C Read multiple bytes of data
 *  @param in: Read_I2C_Addr
 *             p_buffer
 *             number_of_byte
 *  @param out : None
 *  @retval : None
 */
void I2C_Buffer_read(uint16_t Read_I2C_Addr, uint8_t *p_buffer, uint16_t number_of_byte)
{

    I2C_Choose = I2C0_SFR;
    static uint8_t I2C_SLAVE_ADDRESS10BH = 0;
    static uint8_t I2C_SLAVE_ADDRESS10BL = 0;

    /* Enable I2C HW module*/
    I2C_Cmd(I2C_Choose, TRUE);
    /* Clear interrupt flag ISIF */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);

    /* Start bit */
    I2C_Generate_START(I2C_Choose, TRUE);
    /* Wait for the start signal to stabilize */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;

#if (I2C_ADDRESS_WIDTH == I2C_10BIT)
    /* Low 8 bit register address */
    I2C_SLAVE_ADDRESS10BL = Read_I2C_Addr& 0xff;
    /* High bit address */
    I2C_SLAVE_ADDRESS10BH = (Read_I2C_Addr>> 8) & 0xff;
    /* Send slave address */
    I2C_SendData(I2C_Choose, I2C_SLAVE_ADDRESS10BH | 0x01);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;

    /* Send slave 10-bit low address */
    I2C_SendData(I2C_Choose, I2C_SLAVE_ADDRESS10BL);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Determine whether there is an ACK response, if not, stop, if there is, continue to send */
    while (I2C_Get_Ack_Fail_Flag(I2C_Choose))
        ;

#else
    /* Send 7-bit slave address */
    I2C_SendData8(I2C_Choose, Read_I2C_Addr | 0x01);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Determine whether there is an ACK response, if not, stop, if there is, continue to send */
    while (I2C_Get_Ack_Fail_Flag(I2C_Choose))
        ;
#endif

    /* Send read command */
    /* Send slave address and read operation */
    I2C_SendData8(I2C_Choose, Read_I2C_Addr);
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);

    /* Wait for sending to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;
    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);

    while (number_of_byte)
    {

        /* Wait for sending to complete */
        while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
            ;
        /* Determine whether the Buff is full */
        if (I2C_Get_Receive_Buff_Flag(I2C_Choose))
        {
            /* Reply ACK */
            I2C_Ack_DATA_Config(I2C_Choose, I2C_ACKDATA_ACK);
            *p_buffer = I2C_ReceiveData(I2C_Choose);
            /* Clear the ISIF bit of the I2C interrupt flag */
            I2C_Clear_INTERRUPT_Flag(I2C_Choose);
            /* Point to the location where the next read byte will be saved */
            p_buffer++;
        }

        /* Decrement read byte counter */
        number_of_byte--;
    }

    /* Stop bit */
    I2C_Generate_STOP(I2C_Choose, TRUE);

    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Wait for the stop to complete */
    while (!I2C_Get_INTERRUPT_Flag(I2C_Choose))
        ;

    /* Clear the ISIF bit of the I2C interrupt flag */
    I2C_Clear_INTERRUPT_Flag(I2C_Choose);
    /* Clear the I2C stop flag PIF bit */
    I2C_Clear_Stop_Flag(I2C_Choose);
    /* Turn off the I2C module */
    I2C_Cmd(I2C_Choose, FALSE);
}
